package com.hhf.rrd.utils;


import com.hhf.rrd.constant.RegexConstant;
import lombok.extern.slf4j.Slf4j;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符串操作工具类，扩展自 hutool.cn
 *
 * @author huanghaifeng15
 * @date 2022/2/11 13:18
 **/
@Slf4j
public class StringUtils extends org.apache.commons.lang3.StringUtils {
    /**
     *
     */
    private final static Map<String, String> CITY_MAP = new HashMap<>(256);
    /**
     *
     */
    private final static Integer TEN = 10;
    /**
     *
     */
    private final static Integer HUNDRED = 100;
    /**
     *
     */
    private final static Integer THOUSAND = 1000;
    /**
     *
     */
    private final static Integer TEN_THOUSAND = 10000;
    /**
     *
     */
    private final static String QUESTION_MARK = "?";
    /**
     *
     */
    private final static String CONNECTOR_MARK = "&";

    /**
     * 格式化字符串（替换符为%s）
     */
    public static String formatIfArgs(String format, Object... args) {
        if (org.apache.commons.lang3.StringUtils.isEmpty(format)) {
            return format;
        }

        return (args == null || args.length == 0) ? format.replaceAll("%([^n])", "%%$1") : String.format(format, args);
    }

    /**
     * 格式化字符串(替换符自己指定)
     */
    public static String formatIfArgs(String format, String replaceOperator, Object... args) {
        if (isEmpty(format) || isEmpty(replaceOperator)) {
            return format;
        }

        format = replace(format, replaceOperator, "%s");
        return formatIfArgs(format, args);
    }

    /**
     * 替换字符串
     */
    public static String replace(String inString, String oldPattern, String newPattern) {
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(inString) && org.apache.commons.lang3.StringUtils.isNotEmpty(oldPattern) && newPattern != null) {
            int index = inString.indexOf(oldPattern);
            if (index == -1) {
                return inString;
            } else {
                int capacity = inString.length();
                if (newPattern.length() > oldPattern.length()) {
                    capacity += 16;
                }

                StringBuilder sb = new StringBuilder(capacity);
                int pos = 0;

                for (int patLen = oldPattern.length(); index >= 0; index = inString.indexOf(oldPattern, pos)) {
                    sb.append(inString.substring(pos, index));
                    sb.append(newPattern);
                    pos = index + patLen;
                }

                sb.append(inString.substring(pos));
                return sb.toString();
            }
        } else {
            return inString;
        }
    }

    /**
     * 字符串转日期(起止时间)
     *
     * @param nextDays 解析失败后，取今天往后的第几天时间
     * @param strDate  指定解析的日期
     * @return
     */
    public static Date str2Date(String strDate, int nextDays, int defaultAdd) {
        if (StringUtils.isNotEmpty(strDate)){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            try {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(simpleDateFormat.parse(strDate));
                calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + defaultAdd);
                return calendar.getTime();
            } catch (ParseException e) {
                Calendar calendar = Calendar.getInstance();
                calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + nextDays);
                return calendar.getTime();
            }
        }else {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + nextDays);
            return calendar.getTime();
        }
    }

    /**
     * 字符串转日期(起止时间)
     *
     * @param pattern 解析格式
     * @param strDate  指定解析的日期
     * @return
     */
    public static Date str2Date(String strDate, String pattern) throws Exception {
        if (StringUtils.isNotEmpty(strDate)){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
            return simpleDateFormat.parse(strDate);
        }
        throw new ParseException("null of param",2);
    }

    /**
     * 字符串转日期
     *
     * @param strDate  指定解析的日期
     * @return
     */
    public static Date str2Date(String strDate) throws ParseException {
        if (StringUtils.isNotEmpty(strDate)){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return  simpleDateFormat.parse(strDate);
        }else {
            throw new ParseException("null of param",0);
        }
    }

    /**
     * 获取当前年份
     * @return
     */
    public static String getSysYear() {
        Calendar date = Calendar.getInstance();
        return String.valueOf(date.get(Calendar.YEAR));
    }

    /**
     *
     * @param date
     * @param format
     * @return
     */
    public static String date2Str(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    /**
     * 字符串日期增加天数
     * @param date
     * @param num
     * @return
     */
    public static String dateAddDays(String date, int num) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date sDate = sdf.parse(date);
            Calendar c = Calendar.getInstance();
            c.setTime(sDate);
            c.add(Calendar.DAY_OF_MONTH, num);
            return sdf.format(c.getTime());
        }catch (Exception e) {
            log.error("dateAddDays->Exception: ", e);
            return "";
        }
    }



    /**
     * 获取 N 秒前的时间
     * @param seconds
     * @param format
     * @return
     */
    public static String beforeSeconds(int seconds,String format){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND,-1 * seconds);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(calendar.getTime());
    }


    /**
     * Return whether input matches regex of simple mobile.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isMobileSimple(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_MOBILE_SIMPLE, input);
    }

    /**
     * Return whether input matches regex of exact mobile.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isMobileExact(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_MOBILE_EXACT, input);
    }

    /**
     * Return whether input matches regex of telephone number.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isTel(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_TEL, input);
    }

    /**
     * Return whether input matches regex of id card number which length is 15.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isIDCard15(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_ID_CARD15, input);
    }

    /**
     * Return whether input matches regex of id card number which length is 18.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isIDCard18(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_ID_CARD18, input);
    }

    /**
     * Return whether input matches regex of exact id card number which length is 18.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isIDCard18Exact(final CharSequence input) {
        if (isIDCard18(input)) {
            int twoLen = 2;
            int seventeenLen = 17;
            int[] factor = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
            char[] suffix = new char[]{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
            if (CITY_MAP.isEmpty()) {
                CITY_MAP.put("11", "北京");
                CITY_MAP.put("12", "天津");
                CITY_MAP.put("13", "河北");
                CITY_MAP.put("14", "山西");
                CITY_MAP.put("15", "内蒙古");

                CITY_MAP.put("21", "辽宁");
                CITY_MAP.put("22", "吉林");
                CITY_MAP.put("23", "黑龙江");

                CITY_MAP.put("31", "上海");
                CITY_MAP.put("32", "江苏");
                CITY_MAP.put("33", "浙江");
                CITY_MAP.put("34", "安徽");
                CITY_MAP.put("35", "福建");
                CITY_MAP.put("36", "江西");
                CITY_MAP.put("37", "山东");

                CITY_MAP.put("41", "河南");
                CITY_MAP.put("42", "湖北");
                CITY_MAP.put("43", "湖南");
                CITY_MAP.put("44", "广东");
                CITY_MAP.put("45", "广西");
                CITY_MAP.put("46", "海南");

                CITY_MAP.put("50", "重庆");
                CITY_MAP.put("51", "四川");
                CITY_MAP.put("52", "贵州");
                CITY_MAP.put("53", "云南");
                CITY_MAP.put("54", "西藏");

                CITY_MAP.put("61", "陕西");
                CITY_MAP.put("62", "甘肃");
                CITY_MAP.put("63", "青海");
                CITY_MAP.put("64", "宁夏");
                CITY_MAP.put("65", "新疆");

                CITY_MAP.put("71", "台湾");
                CITY_MAP.put("81", "香港");
                CITY_MAP.put("82", "澳门");
                CITY_MAP.put("91", "国外");
            }
            if (CITY_MAP.get(input.subSequence(0, twoLen).toString()) != null) {
                int weightSum = 0;
                for (int i = 0; i < seventeenLen; ++i) {
                    weightSum += (input.charAt(i) - '0') * factor[i];
                }
                int idCardMod = weightSum % 11;
                char idCardLast = input.charAt(17);
                return idCardLast == suffix[idCardMod];
            }
        }
        return false;
    }

    /**
     * Return whether input matches regex of email.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isEmail(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_EMAIL, input);
    }

    /**
     * Return whether input matches regex of url.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isUrl(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_URL, input);
    }

    /**
     * Return whether input matches regex of Chinese character.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isZh(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_ZH, input);
    }

    /**
     * Return whether input matches regex of username.
     * <p>scope for "a-z", "A-Z", "0-9", "_", "Chinese character"</p>
     * <p>can't end with "_"</p>
     * <p>length is between 6 to 20</p>.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isUsername(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_USERNAME, input);
    }

    /**
     * Return whether input matches regex of date which pattern is "yyyy-MM-dd".
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isDate(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_DATE, input);
    }

    /**
     * Return whether input matches regex of ip address.
     *
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isIp(final CharSequence input) {
        return isMatch(RegexConstant.REGEX_IP, input);
    }

    /**
     * Return whether input matches the regex.
     *
     * @param regex The regex.
     * @param input The input.
     * @return {@code true}: yes<br>{@code false}: no
     */
    public static boolean isMatch(final String regex, final CharSequence input) {
        return input != null && input.length() > 0 && Pattern.matches(regex, input);
    }

    /**
     * Return the list of input matches the regex.
     *
     * @param regex The regex.
     * @param input The input.
     * @return the list of input matches the regex
     */
    public static List<String> getMatches(final String regex, final CharSequence input) {
        if (input == null) {
            return Collections.emptyList();
        }
        List<String> matches = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        while (matcher.find()) {
            matches.add(matcher.group());
        }
        return matches;
    }

    /**
     * Splits input around matches of the regex.
     *
     * @param input The input.
     * @param regex The regex.
     * @return the array of strings computed by splitting input around matches of regex
     */
    public static String[] getSplits(final String input, final String regex) {
        if (input == null) {
            return new String[0];
        }
        return input.split(regex);
    }

    /**
     * Replace the first subsequence of the input sequence that matches the
     * regex with the given replacement string.
     *
     * @param input       The input.
     * @param regex       The regex.
     * @param replacement The replacement string.
     * @return the string constructed by replacing the first matching
     * subsequence by the replacement string, substituting captured
     * subsequences as needed
     */
    public static String getReplaceFirst(final String input,
                                         final String regex,
                                         final String replacement) {
        if (input == null) {
            return "";
        }
        return Pattern.compile(regex).matcher(input).replaceFirst(replacement);
    }

    /**
     * Replace every subsequence of the input sequence that matches the
     * pattern with the given replacement string.
     *
     * @param input       The input.
     * @param regex       The regex.
     * @param replacement The replacement string.
     * @return the string constructed by replacing each matching subsequence
     * by the replacement string, substituting captured subsequences
     * as needed
     */
    public static String getReplaceAll(final String input,
                                       final String regex,
                                       final String replacement) {
        if (input == null) {
            return "";
        }
        return Pattern.compile(regex).matcher(input).replaceAll(replacement);
    }

    /**
     * 预约码生成
     *
     * @return
     */
    public static String orderSn(String prefix) {
        Calendar calendar = Calendar.getInstance();
        // 1
        int year = calendar.get(Calendar.YEAR) - 2018;
        // 3
        String day = String.format("%03d", calendar.get(Calendar.DAY_OF_YEAR));
        // 5
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH),
                0, 0, 0);
        String second = String.format("%05d", Instant.now().getEpochSecond() - (calendar.getTime()).toInstant().getEpochSecond());

        return prefix + year + day + second + (Math.random() + "").substring(2, 6);
    }


    /**
     * cache
     */
    private static final Map<String,Long> CACHE = new ConcurrentHashMap<>();
    /**
     * queue
     */
    private static final Queue<Integer> QUEUE = new LinkedList<>();

    /**
     * 判断时间格式”
     *
     * @param timeStr 时间字符串
     * @param pattern
     * @return
     */
    public static boolean isValidDateTime(String timeStr, String pattern) {
        DateFormat formatter = new SimpleDateFormat(pattern);
        try {
            if(formatter.parse(timeStr) != null) {
                Date date = formatter.parse(timeStr);
                return timeStr.equals(formatter.format(date));
            }else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 拼接get请求参数
     *
     * @return
     */
    public static String concatGetParams(String url, Map<String, Object> params) {
        Set<String> keys = params.keySet();
        List<String> sb = new ArrayList<>();
        Iterator<String> it = keys.iterator();
        while (it.hasNext()) {
            if(it.next() != null) {
                String key = it.next();
                if (params.containsKey(key)) {
                    sb.add(new StringBuilder().append(key).append("=").append(params.get(key)).toString());
                }
            }
        }
        String par =  String.join("&", sb);
        if (url.contains(QUESTION_MARK)) {
            if (url.endsWith(QUESTION_MARK) || url.endsWith(CONNECTOR_MARK)) {
                return url + par;
            } else {
                return url + CONNECTOR_MARK + par;
            }
        } else {
            return url + QUESTION_MARK + par;
        }
    }

    /**
     *
     * @param birthday
     * @return
     */
    public static Integer getAge(String birthday) {
        try {
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Date birth = df.parse(birthday);
            Calendar now = Calendar.getInstance();
            Calendar born = Calendar.getInstance();

            now.setTime(new Date());
            born.setTime(birth);

            if (born.after(now)) {
                return 0;
            }

            int age = now.get(Calendar.YEAR) - born.get(Calendar.YEAR);
            if (now.get(Calendar.DAY_OF_YEAR) < born.get(Calendar.DAY_OF_YEAR)) {
                age -= 1;
            }
            return age;
        } catch (ParseException e) {
            log.error("getAge->ParseException: ", e);
            return 0;
        }
    }

    /**
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        for (int i = 0; i < str.length(); i++){
            if (!Character.isDigit(str.charAt(i))){
                return false;
            }
        }
        return true;
    }

    /**
     * 通过身份证号码获取出生日期、性别、年龄
     * @param idCardNum
     * @return 返回的出生日期格式：1990-01-01   性别格式：F-女，M-男
     */
    public static String getBirthday(String idCardNum) {
        String birthday = "";

        char[] number = idCardNum.toCharArray();
        boolean flag = true;
        int fifteenLen = 15;
        int eighteenLen = 18;
        if (number.length == fifteenLen) {
            for (char c : number) {
                if (!flag) {
                    return null;
                }
                flag = Character.isDigit(c);
            }
        } else if (number.length == eighteenLen) {
            for (int x = 0; x < number.length - 1; x++) {
                if (!flag) {
                    return null;
                }
                flag = Character.isDigit(number[x]);
            }
        }
        if (flag && idCardNum.length() == fifteenLen) {
            birthday = "19" + idCardNum.substring(6, 8) + "-"
                    + idCardNum.substring(8, 10) + "-"
                    + idCardNum.substring(10, 12);
        } else if (flag && idCardNum.length() == eighteenLen) {
            birthday = idCardNum.substring(6, 10) + "-"
                    + idCardNum.substring(10, 12) + "-"
                    + idCardNum.substring(12, 14);
        }

        return birthday;
    }

    /**
     * 生成6位随机数
     * @return
     */
    public static String getRandomNumSix() {
        return String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
    }

    /**
     *
     * @param text
     * @return
     */
    public static int getCount(String text){
        int amount = 0;
        for(int i = 0;i<text.length();i++){
            boolean matches = Pattern.matches("^[\u4E00-\u9Fa5]{0,}$", new StringBuilder().append(text.charAt(i)).toString());
            if(matches){
                amount ++;
            }
        }
		return amount;
    }

    /**
     * 格式化输出时间
     * @param created
     * @return
     */
    public static String formatDate(String created) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try{
            Date parseDate = simpleDateFormat.parse(created);
            return simpleDateFormat.format(parseDate);
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 格式化输出时间
     * @param created
     * @return
     */
    public static String formatDateAll(String created) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try{
            Date parseDate = simpleDateFormat.parse(created);
            return simpleDateFormat.format(parseDate);
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 包含大小写字母及数字且在6-16位
     * 是否包含 字母和数字
     *
     * @param password
     * @return
     */
    public static boolean checkPassword(String password) {
        boolean isDigit = false;//定义一个boolean值，用来表示是否包含数字
        boolean isLetter = false;//定义一个boolean值，用来表示是否包含字母
        for (int i = 0; i < password.length(); i++) {
            if (Character.isDigit(password.charAt(i))) {   //用char包装类中的判断数字的方法判断每一个字符
                isDigit = true;
            } else if (Character.isLetter(password.charAt(i))) {  //用char包装类中的判断字母的方法判断每一个字符
                isLetter = true;
            }
        }
        String passwordRegex = "^[a-zA-Z0-9]{6,16}$";
        return isDigit && isLetter && password.matches(passwordRegex);
    }



    /**
     * 获取JSON某一字段
     *
     * @param jsonStr json字符串
     * @param key key
     * @return value
     */
    public static String getJsonValue(String jsonStr, String key) {
        try {
            if (StringUtils.isNotEmpty(jsonStr)) {
                key = "\"" + key.trim() + "\"";
                int index = jsonStr.indexOf(key) + key.length() + 1;
                if (index > key.length() + 1) {
                    // 先截逗号，若是最后一个，截“｝”号，取最小值
                    int end = jsonStr.indexOf(',', index);
                    if (end == -1) {
                        end = jsonStr.indexOf('}', index);
                    }
                    String result = jsonStr.substring(index, end);
                    // 过滤引号或空格
                    return cleanBlank(result);
                }
            }
            return "";
        }catch (Exception e){
            log.error("",e);
            return "";
        }
    }


    /**
     * 清除入参全角空格及转义字符，及双引号
     */
    public static String cleanBlank(String str){
        boolean isReplace = str != null && (str.contains("\\") || str.contains("　") || str.contains("\""));
        if (isReplace) {
            String replaceFlag = str.replace("\\", "");
            return replaceFlag.replace("\"", "").replaceAll("　", "").trim();
        }
        return str;
    }

    /**
     * 根据条件对字符串做位置替换
     * @param preNum
     * @param endNum
     * @param sourceStr
     * @param replaceStr
     * @return
     */
    public static String replace(int preNum, int endNum, String sourceStr, String replaceStr){
        if(isBlank(sourceStr)) {
            return sourceStr;
        }
        int  length = sourceStr.length();
        if (preNum > length){
            return sourceStr;
        }
        if (length < endNum+preNum){
            return sourceStr.substring(0,preNum)+replaceStr;
        }
        return sourceStr.substring(0,preNum)+ replaceStr + sourceStr.substring(length-endNum, length);
    }
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
//        System.out.println(checkPassword("11111111"));
//        System.out.println(checkPassword("asd11111111"));
//        System.out.println(checkPassword("weqrwrqwwq"));
//        System.out.println(checkPassword("111qwer.11111"));
//        System.out.println(getBirthday("150429199005183431"));
        System.out.println(replace(3,3, "15789895789535", "****"));
    }

}
